//
// SIKE-Weierstrass
//
// InfoSec Global Inc., 2017
// Basil Hess <basil.hess@infosecglobal.com>
//

#include <sike_params.h>
#include <stdlib.h>
#include <fp2.h>

const sike_params_raw_t SIKEp503 = {
  .name = "SIDHp503",

  .p    = "0x4066F541811E1E6045C6BDDA77A4D01B9BF6C87B7E7DAF13085BDA2211E7A0ABFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
  .lA   = "2",
  .eA   = "250",
  .lB   = "3",
  .eB   = "159",

  .xQA0 = "0x97453912E12F3DAF32EEFFD618BD93D3BBBF399137BD39858CADEFAE382E42D6E60A62FD62417AD61A14B60DB26125273EC980981325D86E55C45E3BB46B1",
  .xQA1 = "0x0",
  .yQA0 = "1987049932037212231973968721636384214972205133977039273988230852499878860087551334883949927898253758830285058762468308465162679988904515957230072487266",
  .yQA1 = "0x0",

  .xPA0 = "0x1F6D52A7563BB9356B98A116A0CA9775DBB7382EB29E24E45299D8939959EAEEB47FF3113F60882D12103E4B8B8CD2B97DA14657AE8C128BE82209D2DDFCA9",
  .xPA1 = "0x2D44C3FAD24E4CBDDC8A2D9DE336A92A9912EE6D09E2DD5C33AB26D60A268AC91F38E1AF4C2D5BFA2B87DD55C8CA6019C6B0C08ED92B5AEB6C65A8E06E53E9",
  .yPA0 = "12402670229954461900243207734449693225303657751926677227304935333873827323904820029638475469172551832161453096678656868712338858522536396125689860052722",
  .yPA1 = "11484172786196667495756436991434786299116769971386010691970879646160084751382582763874471285970900726171894223446389193262702850091090645566995537544188",

  .xRA0 = "0x173775ECBEC79C78FD1ED5FE36075AACE1F53F8FFB97D2A7E80DFC2875E77EC72D1D4A99E13353EC9D147BADD96126948A72B30BDD7CEBAD7B54F8DDB5CD06",
  .xRA1 = "0x2EAA224DDDA149BBBB9089D2B2C471D068ECA203465CE97DBC1C8ED0EBB0FF90E4FBE7E266BBA99CBAE051797B4D35D28E36C1B1CB994AEEED1CB59FE5015",

  .xQB0 = "0x1E7D6EBCEEC9CFC47779AFFD696A88A971CDF3EC61E009DF55CAF4B6E01903B2CD1A12089C2ECE106BDF745894C14D7E39B6997F70023E0A23B4B3787EF08F",
  .xQB1 = "0x0",
  .yQB0 = "9564971801753807400478228934375841749481319953281777094488741482509849184130722887054182386244045249745595750995671613818127043259502592250077272547110",
  .yQB1 = "0x0",

  .xPB0 = "0x21B7098B640A01D88708B729837E870CFF9DF6D4DF86D86A7409F41156CB5F7B8514822730940C9B51E0D9821B0A67DD7ED98B9793685FA2E22D6D89D66A4E",
  .xPB1 = "0x2F37F575BEBBC33851F75B7AB5D89FC3F07E4DF3CC52349804B8D17A17000A42FC6C5734B9FCFDE669730F3E8569CEB53821D3E8012F7F391F57364F402909",
  .yPB0 = "6042268580734125707717621508153042989851420121634015373341145209104488831520712101753537907250478492139591407443828369481830969676778177861667995374",
  .yPB1 = "11447096058130221143247887717568201657458833667044902384551791107436497449771561224009904487909003128602409050019064144280311375906163106081290231909056",

  // .xRB0 = "0xD4818D120A24ABF48DB51D129E6B1F24F4BBB2C16FACC0C8C06323EEEC2FA5B5E887E17226417B1907310BFE6784FDEBBAC8C2A9ABBE753F52259A7B7D70E",
  // .xRB1 = "0x19E75F0F03312D22CBBF153747525D89E5155BABB8BF0C130CB567CA532F69AAF57EA7682B9957021D90414433ABBEEDC233E9082185781C16724C8C356777",

  .crypto_bytes = 16,
  .msg_bytes = 24,
};

const sike_params_raw_t SIKEp751 = {
  .name = "SIDHp751",

  .p    = "0x6FE5D541F71C0E12909F97BADC668562B5045CB25748084E9867D6EBE876DA959B1A13F7CC76E3EC968549F878A8EEAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
  .lA   = "2",
  .eA   = "372",
  .lB   = "3",
  .eB   = "239",

  .xQA0 = "0x3E82027A38E9429C8D36FF46BCC93FA23F89F6BE06D2B1317AD90438621783FDB7A4AD3E83E86CAE096D5DB822C98E561E008FA0E3F3B9AC2F40C56D6FA4A58A20449AF1F1335661D14AB7347693632646086CE3ACD54B0346F5CCE233E9",
  .xQA1 = "0x0",
  .yQA0 = "5528941793184617364511452300962695084942165460078897881580666552736555418273496645894674314774001072353816966764689493098122556662755842001969781687909521301233517912821073526079191975713749455487083964491867894271185073160661",
  .yQA1 = "0x0",

  .xPA0 = "0x54921C31F0DC9531CB890FC5EC66DF2E7F0D55761363C6E375DA69B0682CABE5C0FFFCBE6E1AD46563F042FA06B9F207FCF3CDD2673652828FF50C3F7B755C0BE072950D16CA747C146775C0267A401FFC738B03A49E9A36B39572AFB363",
  .xPA1 = "0x28849BC0D81E01993137A5B63D6E633C4E97AB4FF118CCF63DFE623092AC86B6D4A9B751797CBA1A177500E9EB5AF7852B7DF02C334844D652EFC4729178A1DBAD8CA47BB7E757C6D43B799811A63BEBE649C18101F03AD752CDCD73BF66",
  .yPA0 = "2348531686306321473179237493901121101251261468708168021580041545642486729428752960855318604207691907539342759589532842957869999158406882896511632860760439655015973310423659754374353436749267438248809315524898240603295886326908",
  .yPA1 = "1224222198803461938137264084051250811019119970701955865178638700511225375942293449806297653158762668114930395406317416617920083632175842297633972417496387192903253229514049642665117382248371773491158498833247595872501914850333",

  .xRA0 = "0x22A0B5A35A2B0C56135A7CEC5CFB97964A7C6226FE909F374362A8ECA3AB14A1B7B0C87AC875DCE5888D83B623BF0011A4AC138F62EF6B2D2D84F636548A9F920F238336E5A36E45E4055940E3C94385B8FC5374396432EEF2AE178CEFDD",
  .xRA1 = "0xF9C4AFCDA809C3358B096B250C69B20310FDF2EF631711AA4EFEC49A4E76483F320B793F2EBC63365EED14AA3F6EA33FEB56796F011BA6C6DFB4D0A00AAC4D2786646D914AD026CBB4A592EC74B5485372E51382D44528DD491B83D9547",

  .xQB0 = "0x2F1D80EF06EF960A01AB8FF409A2F8D5BCE859ED725DE145FE2D525160E0A3AD8E17B9F9238CD5E69CF26DF237429BD3778659023B9ECB610E30288A7770D3785AAAA4D646C576AECB94B919AEEDD9E1DF566C1D26D376ED2325DCC93103",
  .xQB1 = "0x0",
  .yQB0 = "106866937607440797536385002617766720826944674650271400721039514250889186719923133049487966730514682296643039694531052672873754128006844434636819566554364257913332237123293860767683395958817983684370065598726191088239028762772",
  .yQB1 = "0x0",

  .xPB0 = "0x5FD1A3C4DD0F630974196FED3519152BC7098B9E2B121ECA46BD10A5CC9F4BCC6C689B8E4C063B3798075FCEE6EDAA9EB108B3CD00495CF04DD8CE4A08FBE685A127D40E45F4CF45098A578DEB44368699394C43BFC9BC5E00052F78E8D",
  .xPB1 = "0x2B88A03360B3389547732C9140C05DEA6516881FE108211BE887CC43FCB80C06A1D86FF5457D3BB7DB936394EC33821AA39333A60AF84B537974CFA0BA8287D699D2BF79BA559026C64A6ED610501D2357C10B9A6C8F837424922275ACBF",
  .yPB0 = "7746135198776817861643474248238875207015697800812491926156073343557054056551059025900634785953747738601401683852068406930757977978550573916590141124686284315443160498988187877881638621763057962222578298556686495193360392071641",
  .yPB1 = "398440269588497916470838836403523933824250295535791204569625366738288867085661379405222698631765637443515833035498914192038056822450333735247267055787818949513673228749273008963530759037116387659371102647687072945797796756830",

  // .xRB0 = "0x77B3BB69009428A327D43CA60169715F547454F88CD017B32DF58A7252C2B3C3D00D52CCD3133D54041D8BCAEA291F2057202328712CD395575CD7CCD3CE70C0A1EBF633BA946559458878F41F9FDD1727E2C31125B2FE5B71306704829",
  // .xRB1 = "0x6D91393A57DBF47FD6DCF841F17ECD719CAE1D33C6832A75B0F168855BCC38D2A4792DFF9BC86DEACA10B1AA808D539B167D73BBA32168687FA3F85AE93A1ADDE5BD1FD5B681DCC6C34454D4496976C22D80C95E42B12576FC0FB4074B9F",

  .crypto_bytes = 24,
  .msg_bytes = 32,
};

const sike_params_raw_t SIKEp964 = {
  .name = "SIDHp964",

  .p    = "0x86B5BFF7643C64F7A10028248AD4FC4B150CBAA75A2A1FA44CBAB245135469BAB093F2B8DAD5281E7E56EF6AA57A94749ABB38EAB467ACDE5451CD4BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
  .lA   = "2",
  .eA   = "486",
  .lB   = "3",
  .eB   = "301",

  .xQA0 = "0x1CD5AEB4E02DBE2CEB712A45EED7720D3EA94116F1E45C834FDFF3A867BBB267BF8F5F9B19C369F7AFE141B85D591243E7310B6D02E78DB888615254DF178C1F75F2BDAF703E83BB97DBCDC3DFDB60BA385EC8F42D4AD150521ECA6EC4D3086A7783698A71544E10A45EA605E1B86A8947F14FA2E03845DAE",
  .xQA1 = "0x0",
  .yQA0 = "21259155310092693367207800948423431215791386018819028716455539536796553708996291269826547555421095902382686336579371961161523756342711987689338090474970300038026209679518461437806070242615092645617317040995745115679099628158311477687681408458457995606179248503977260347932511407989585793890",
  .yQA1 = "0x0",

  .xPA0 = "0x6ED767E2804975D8180368FB9A72CE64E838A54974865BFF1A86AEF07D6171A8A4DF351F1D4C94AAF82BD6EBD396F334248282F5073178AB57B906BEF89A2A152A10D04A5B20A0FFF96B0B48F0599FC9BD2AD52E081BB7FEA7B5E8BF4C3B0AB130731F4C5A974CFA5AD6781217A20F9ECD30691D9D1941D03",
  .xPA1 = "0x3FE63FBDCA589518A3DA694ECC8B659346693C45BD8AC86B6F0C778CF290C9F429163FEF64AFAD182ADE1B0C4DFC8CF29C35455C7BA69C22559F2E0D420AE05BB0AE3ADC09A4A0AF28CE1A1C5931710337AA68884EFCCD60AC76FD3F17ED50205305509E05955F60D5008D788B83F5FA457FD79ECDC7179D1",
  .yPA0 = "2970840439342020390417664748039008065284427584235923159554415486156118966057405688062110062249251574688140871329337055076146949923303175372215248345346092802123717124668939307075294554058042328359849131630898180083546907357615854208639630030896088382996716590713389407809662023349562626642",
  .yPA1 = "70368670069799361737320824239398446387355530314796269112021344475521834837142312519957745142729764153232403813481153129977947562116216761021391134951127807424957247808211716221939812750073212916453651207293455254361077889821714063772450827256200358589653324636381359380072778785403012959517",

  .xRA0 = "0x844F024B8D993B66048C9DA7F1724AE2E4C6162F84804FE3FE290FBEB5ABF7DF25C39512177C8E4A47A35F8ECD037B699E34F58EF675AE188A1537838A4DDBA69FC7BC3FACB7E3815F3031244AF1BCCE195AF45B42A587EE87A00BF2DA1E972D8D662F4DC5EC1CDB103D9EED2215D4DD7480049858925A63A",
  .xRA1 = "0x735F06B9766B69FF917835EADC539A00FFC186ED25947F701FDA7EDEAF517039F9B0DA1721FDAE9784838C75B46A452DC902EC8DD1F4625643B42C596C2CF04045A7AA8043F07C9A9F82611D202F06834512A3803EF64650E5309163F25CCC336CC8527649E340F59CDDFB51B24D1C02E8CB2653E7A05B709",

  .xQB0 = "0x381DBCAB1EE7A4CA3192CDA853F4E0F426522EB9D3277421C29D73CC4F70BEFE7009767C4AE4516003B237223422C0E752ACD9D8FCE07263D2C1D101308C0B97EDB8D4A8C53C2064B05DF9A61E8216CA1FFAC55F4CA04397252704945C27136A056F6B5CF8838B7F652BC16C1392B559736CAF63BF0058A53",
  .xQB1 = "0x0",
  .yQB0 = "16435649431840520991545576983940413502348075578051019619143251821632054380264033871393405424421569803374966836195059018341991035483549565009680038786346574333230129471868641067265848532566966923949992268805245390272654391505694183027334529441775087521430318596746021513405330259638546892423",
  .yQB1 = "0x0",

  .xPB0 = "0x4FE46F0B009171C870FE840B7FD0C3F1493813CD125C2191C9FA4BDE40941A603124F1B81BBFBEBFDAC06F80807562639FC61A57962AE6E6B7EE793CF7B359746FEB0DA110D704681F83EF6B440DC5DEDD2A4247149D0A44C452ED374A394319A8888A2A09CC4A0F35A07AA3D248CF7803E77EAD2A4BEA308",
  .xPB1 = "0x6DD4FC1768E1ADEE54DC4E41CFAA7B8104644DD690616D374A9139013FD847C2CD11BA6CA4C4FC26A63FE198B666B7912FBF889E991CF4B903651F4414CD4AA50BC02CE2EC986A7BFC1A8D364F93410ADE3B959FF1F036F36EF3AFF88D28DB5008276C3402158ADB4A44BAECED2AF6503093FD8B6A58EC136",
  .yPB0 = "38164714705284732954209792690355354444395801719389769161236295243750190862796401334023948611431607652443553230191649263504205267979113334042201679505713267806070925742222733136304237530687015175041568229814429317211303604307964209993859583190442710649806582896987079823963957731251375871936",
  .yPB1 = "72761592693820377158284533769530307348441782670758972830425034100648259739873648989860170128413087983967026556421038444213850433466268419733862182827042455084110606055983618542711545835964990590827922995016407768016838542601712359608127723113495547955291776584839900848913269610304347065561",

  // .xRB0 = "0x7DE290085EBBDC801A1D6292D1F2E89FF463669ED2F5F6C02B8010A75245C4D3984002821B8A243C756512A5FC1FC0867A84583D76B0404E7E73CEB7071E2AE3BF43BFB77A87BC98FDF888E285CD4A3C94E4D1795009E41EDB8A3AD8F81321138E4A87B69416AEFF094E541F48681863BAD30FB2F32EA019A",
  // .xRB1 = "0x7A2A2DFA4FB56733660ACCB80308A4482B1A46D3B9BB20313F164CC809A3A6B4D2FBC43574994354DC06D409F9F647E82F4F05D6C5A70E340DF4B95559787F82EAD7F7295590FDCD9D54B8001094DC80929EF4C5ABB8E388A53AA0BD388D890B5980F1FD19404025B582C640DDFDA1BDF46D370464A812732",

  .crypto_bytes = 32,
  .msg_bytes = 40,
};

int
sike_setup_params(const sike_params_raw_t *raw, sike_params_t *params) {
  // Base curve -> Coefficients are null
  weier_curve_t* EA = &params->EA;
  weier_curve_t* EB = &params->EB;

  params->eA = (unsigned long) strtol(raw->eA, NULL, 0);
  params->eB = (unsigned long) strtol(raw->eB, NULL, 0);

  params->lA = (unsigned long) strtol(raw->lA, NULL, 0);
  params->lB = (unsigned long) strtol(raw->lB, NULL, 0);

  ff_Params* ffpA = malloc(sizeof(ff_Params));
  ff_Params* ffpB = malloc(sizeof(ff_Params));


  set_gmp_fp_params(ffpA);
  set_gmp_fp_params(ffpB);

  EA->ffData = ffpA;

  fp_Init(ffpA, params->p);
  fp_ImportHex(raw->p, params->p);

  fp_Init(ffpA, params->ordA);

  mp_pow(params->lA, params->eA, params->ordA);
  params->msbA = mp_sizeinbase(params->ordA, 2);

  fp_Init(ffpA,  EA->ffData->mod);

  fp_Init(ffpA, EA->P.x.x0);
  fp_Init(ffpA, EA->P.x.x1);
  fp_Init(ffpA, EA->P.y.x0);
  fp_Init(ffpA, EA->P.y.x1);
  fp_Init(ffpA, EA->Q.x.x0);
  fp_Init(ffpA, EA->Q.x.x1);
  fp_Init(ffpA, EA->Q.y.x0);
  fp_Init(ffpA, EA->Q.y.x1);

  fp_ImportHex(raw->p,    EA->ffData->mod);


  fp_ImportHex(raw->xPA0, EA->P.x.x0);
  fp_ImportHex(raw->xPA1, EA->P.x.x1);
  fp_ImportHex(raw->yPA0, EA->P.y.x0);
  fp_ImportHex(raw->yPA1, EA->P.y.x1);
  fp_ImportHex(raw->xQA0, EA->Q.x.x0);
  fp_ImportHex(raw->xQA1, EA->Q.x.x1);
  fp_ImportHex(raw->yQA0, EA->Q.y.x0);
  fp_ImportHex(raw->yQA1, EA->Q.y.x1);

  fp2_Init_set(ffpA, &EA->a, 1, 0);
  fp2_Init_set(ffpB, &EA->b, 0, 0);

  EB->ffData = ffpB;

  fp_Init(ffpB, params->ordB);

  mp_pow(params->lB, params->eB, params->ordB);
  params->msbB = mp_sizeinbase(params->ordB, 2);

  fp_Init(ffpB, EB->ffData->mod);

  fp_Init(ffpB, EB->P.x.x0);
  fp_Init(ffpB, EB->P.x.x1);
  fp_Init(ffpB, EB->P.y.x0);
  fp_Init(ffpB, EB->P.y.x1);
  fp_Init(ffpB, EB->Q.x.x0);
  fp_Init(ffpB, EB->Q.x.x1);
  fp_Init(ffpB, EB->Q.y.x0);
  fp_Init(ffpB, EB->Q.y.x1);

  fp_ImportHex(raw->p,    EB->ffData->mod);

  fp_ImportHex(raw->xPB0, EB->P.x.x0);
  fp_ImportHex(raw->xPB1, EB->P.x.x1);
  fp_ImportHex(raw->yPB0, EB->P.y.x0);
  fp_ImportHex(raw->yPB1, EB->P.y.x1);
  fp_ImportHex(raw->xQB0, EB->Q.x.x0);
  fp_ImportHex(raw->xQB1, EB->Q.x.x1);
  fp_ImportHex(raw->yQB0, EB->Q.y.x0);
  fp_ImportHex(raw->yQB1, EB->Q.y.x1);

  fp2_Init_set(ffpB, &EB->a, 1, 0);
  fp2_Init_set(ffpB, &EB->b, 0, 0);

  params->crypto_bytes = raw->crypto_bytes;
  params->msg_bytes = raw->msg_bytes;

  return 0;
}

int
sike_teardown_params(sike_params_t *params) {
  weier_curve_t* EA = &params->EA;
  weier_curve_t* EB = &params->EB;

  ff_Params* ffpA = EA->ffData;
  ff_Params* ffpB = EB->ffData;

  fp_Clear(ffpA, params->p);

  fp_Clear(ffpA,  EA->ffData->mod);
  fp_Clear(ffpA,  params->ordA);

  fp_Clear(ffpA, EA->P.x.x0);
  fp_Clear(ffpA, EA->P.x.x1);
  fp_Clear(ffpA, EA->P.y.x0);
  fp_Clear(ffpA, EA->P.y.x1);
  fp_Clear(ffpA, EA->Q.x.x0);
  fp_Clear(ffpA, EA->Q.x.x1);
  fp_Clear(ffpA, EA->Q.y.x0);
  fp_Clear(ffpA, EA->Q.y.x1);

  fp2_Clear(ffpA, &EA->a);
  fp2_Clear(ffpB, &EA->b);

  fp_Clear(ffpB, EB->ffData->mod);
  fp_Clear(ffpB, params->ordB);

  fp_Clear(ffpB, EB->P.x.x0);
  fp_Clear(ffpB, EB->P.x.x1);
  fp_Clear(ffpB, EB->P.y.x0);
  fp_Clear(ffpB, EB->P.y.x1);
  fp_Clear(ffpB, EB->Q.x.x0);
  fp_Clear(ffpB, EB->Q.x.x1);
  fp_Clear(ffpB, EB->Q.y.x0);
  fp_Clear(ffpB, EB->Q.y.x1);

  fp2_Clear(ffpB, &EB->a);
  fp2_Clear(ffpB, &EB->b);

  free(ffpA);
  free(ffpB);
  return 0;
}